﻿using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Markup;
using System.Windows.Media;
using UBCon.Ribbon.Interfaces;

namespace UBCon.Ribbon
{
    /// <summary>
    /// Represents a control that creates a container which has a header for the user interface (UI) content.
    /// </summary>
    [ContentProperty("Items")]
    public class ContextualTabItemsGroup : Control, IRibbonControl
    {
        #region Constructors

        //------------------------------------------------------
        //
        //  Constructors
        //
        //------------------------------------------------------
        /// <summary>
        /// Defauls static constructor.
        /// </summary>
        static ContextualTabItemsGroup()
        {
            Type ownerType = typeof(ContextualTabItemsGroup);

            ContextualTabItemsGroup.VisibilityProperty.OverrideMetadata(ownerType,
                new FrameworkPropertyMetadata(
                    Visibility.Collapsed, new PropertyChangedCallback(OnVisibilityChanged),
                    new CoerceValueCallback(CoerceVisibility)));
        }

        /// <summary>
        /// Initializes a new instance of the UBCon.Ribbon.ContextualTabItemsGroup class.
        /// </summary>
        public ContextualTabItemsGroup()
            : base()
        {
            Items = new ObservableCollection<RibbonTabItem>();
        }

        #endregion

        //------------------------------------------------------
        //
        //  Properties
        //
        //------------------------------------------------------
        #region Properties

        /// <summary>
        /// Gets or sets instance of ContextualItemsHeader class which represents header control for 
        /// grouped contextual tab items. 
        /// </summary>
        internal ContextualItemsHeader Header { get; set; }

        /// <summary>
        /// Gets or sets a collection contexual RibbonTabItem control.
        /// This is a dependency property.
        /// </summary>
        public ObservableCollection<RibbonTabItem> Items
        {
            get { return (ObservableCollection<RibbonTabItem>)GetValue(ItemsProperty); }
            set { SetValue(ItemsProperty, value); }
        }

        /// <summary>
        /// Identifies UBCon.Ribbon.ContextualTabItemsGroup.Items dependency property.
        /// </summary>
        public static readonly DependencyProperty ItemsProperty =
            DependencyProperty.Register("Items", typeof(ObservableCollection<RibbonTabItem>), typeof(ContextualTabItemsGroup), new PropertyMetadata(null));

        /// <summary>
        /// Gets or sets ContextualTabItemsGroup title. This is a dependency property.
        /// </summary>
        public string Title
        {
            get { return (string)GetValue(TitleProperty); }
            set { SetValue(TitleProperty, value); }
        }

        /// <summary>
        /// Identifies UBCon.Ribbon.ContextualTabItemsGroup.Title dependency property.
        /// </summary>
        public static readonly DependencyProperty TitleProperty =
            DependencyProperty.Register("Title", typeof(string), typeof(ContextualTabItemsGroup), new PropertyMetadata(null));

        [Bindable(true),
        ReadOnly(false),
        Category("Appearence")]
        /// <summary>
        /// Gets or sets ContextualTabItemsGroup brush. This is a dependency property.
        /// </summary>
        public Brush Brush
        {
            get { return (Brush)GetValue(BrushProperty); }
            set { SetValue(BrushProperty, value); }
        }

        /// <summary>
        /// Identifies UBCon.Ribbon.ContextualTabItemsGroup.Brush dependency property.
        /// </summary>
        public static readonly DependencyProperty BrushProperty =
            DependencyProperty.Register("Brush", typeof(Brush), typeof(ContextualTabItemsGroup), new PropertyMetadata(null));

        /// <summary>
        /// Gets or sets an instance of UBCon.Ribbon.Ribbonbar class which owns this ContextualTabItemsGroup control.
        /// This is a dependency property.
        /// </summary>
        internal RibbonBar RibbonBar
        {
            get { return (RibbonBar)GetValue(RibbonBarProperty); }
            set { SetValue(RibbonBarProperty, value); }
        }

        /// <summary>
        /// Identifies UBCon.Ribbon.ContextualTabItemsGroup.RibbonBar dependency property.
        /// </summary>
        internal static readonly DependencyProperty RibbonBarProperty =
            DependencyProperty.Register("RibbonBar", typeof(RibbonBar), typeof(ContextualTabItemsGroup), new PropertyMetadata(null));

        /// <summary>
        /// Gets or sets a default index by which RibbonTabItem selected when 
        /// left mouse button is pressed while the mouse pointer is over the header. This is a dependency property.
        /// </summary>
        public int DefaultIndex
        {
            get { return (int)GetValue(DefaultIndexProperty); }
            set { SetValue(DefaultIndexProperty, value); }
        }

        /// <summary>
        /// Identifies UBCon.Ribbon.ContextualTabItemsGroup.DefaultIndex dependency property.
        /// </summary>
        public static readonly DependencyProperty DefaultIndexProperty =
            DependencyProperty.Register("DefaultIndex", typeof(int), typeof(ContextualTabItemsGroup),
            new PropertyMetadata(
                -1, 
                new PropertyChangedCallback(OnDefaultIndexChanged),
                new CoerceValueCallback(CoerceDefaultIndex)));
        
        #endregion

        //------------------------------------------------------
        //
        //  Depenency Property Changed Callbacks
        //
        //------------------------------------------------------
        #region Depenency Property Changed Callbacks

        /// <summary>
        /// Invoked when Visibility property changes.
        /// </summary>
        /// <param name="sender">Type: System.Windows.DependencyObject. The DependencyObject on which the property has changed value.</param>
        /// <param name="e">Type: System.Windows.DependencyPropertyChangedEventArgs. Event data that is issued by any event that tracks changes to the effective value of this property.</param>
        private static void OnVisibilityChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) 
        {
            ContextualTabItemsGroup group = sender as ContextualTabItemsGroup;
            RibbonWindow window = RibbonHelper.GetWindow(group);
            if (window != null) 
            {
                Visibility newValue = (Visibility)e.NewValue, oldValue = (Visibility)e.OldValue;
                if (newValue == Visibility.Collapsed)
                {
                    if (window.InternalRibbonBar != null)
                    {
                        RibbonBar bar = window.InternalRibbonBar;
                        foreach (var item in group.Items)
                        {
                            if (bar.Items.Contains(item))
                            {
                                bar.Items.Remove(item);
                            }
                        }

                        window.RemoveContuxtualHeader(group.Header);
                        
                    }
                }
                window.UpdateTitleLocation(window);
            }
           
        }

        /// <summary>
        /// Coerces Visibility property.
        /// </summary>
        /// <param name="sender">Type: System.Windows.DependencyObject. The object that the property exists on. When the callback is invoked, the property system will pass this value.</param>
        /// <param name="value">Type: System.Object. The new value of the property, prior to any coercion attempt.</param>
        /// <returns>Type: System.Object. The coerced value (with appropriate type). </returns>
        private static object CoerceVisibility(DependencyObject sender, object value)
        {
            ContextualTabItemsGroup groupC = sender as ContextualTabItemsGroup;

            Visibility pendingValue = groupC.Items.Count > 0 ? (Visibility)value : Visibility.Collapsed;

            if (pendingValue == Visibility.Visible)
            {
                RibbonWindow window = RibbonHelper.GetWindow(groupC);
                if (window != null && window.InternalRibbonBar != null)
                {
                    RibbonBar bar = window.InternalRibbonBar;
                    foreach (var item in groupC.Items)
                    {
                        if (item.IsSelected)
                        {
                            item.ClearValue(RibbonTabItem.IsSelectedProperty);
                        }
                        item.SetValue(RibbonTabItem.IsContextualPropertyKey, true);
                        item.ContextualTabItemsGroup = groupC;
                        bar.AddNewItem(item);
                    }
                    groupC.CoerceValue(ContextualTabItemsGroup.DefaultIndexProperty);
                    if (groupC.DefaultIndex >= 0) 
                    {
                        RibbonTabItem tabItem = groupC.Items[groupC.DefaultIndex];
                        bar.SetValue
                            (
                                RibbonBar.SelectedIndexProperty, 
                                bar.Items.IndexOf(bar.ItemContainerGenerator.ContainerFromItem(tabItem))
                            );
                    }
                    if (groupC.Header == null) 
                    {
                        ContextualItemsHeader header = new ContextualItemsHeader();

                        BindingOperations.SetBinding
                            (
                                header,
                                ContextualItemsHeader.BrushProperty,
                                new Binding("Brush")
                                {
                                    Source = groupC,
                                    Mode = BindingMode.TwoWay
                                }
                            );
                        BindingOperations.SetBinding
                            (
                                header,
                                ContextualItemsHeader.TitleProperty,
                                new Binding("Title")
                                {
                                    Source = groupC,
                                    Mode = BindingMode.TwoWay
                                }
                            );
                        groupC.Header = header;
                    }
                    window.AddContextualHeader(groupC.Header);
                    //window.InternalRibbonBar.UpdateHiddenRectangle(groupC.);
                }
            }
            return pendingValue;
        }

        /// <summary>
        /// Invoked when DefaultIndex property changes.
        /// </summary>
        /// <param name="sender">Type: System.Windows.DependencyObject. The DependencyObject on which the property has changed value.</param>
        /// <param name="e">Type: System.Windows.DependencyPropertyChangedEventArgs. Event data that is issued by any event that tracks changes to the effective value of this property.</param>
        private static void OnDefaultIndexChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) { }

        /// <summary>
        /// Coerces DefaultIndex property.
        /// </summary>
        /// <param name="sender">Type: System.Windows.DependencyObject. The object that the property exists on. When the callback is invoked, the property system will pass this value.</param>
        /// <param name="value">Type: System.Object. The new value of the property, prior to any coercion attempt.</param>
        /// <returns>Type: System.Object. The coerced value (with appropriate type). </returns>
        private static object CoerceDefaultIndex(DependencyObject sender, object value) 
        {
            ContextualTabItemsGroup group = sender as ContextualTabItemsGroup;
            int pendingValue = (int)value;
            if (pendingValue >= 0 && pendingValue <= group.Items.Count - 1) 
            {
                return value;
            }
            return -1;
        }
        #endregion

        //------------------------------------------------------
        //
        //  Overrides
        //
        //------------------------------------------------------
        #region Overrides

        #endregion


        //------------------------------------------------------
        //
        //  Public Methods
        //
        //------------------------------------------------------
        #region Public Methods
        #endregion

        //------------------------------------------------------
        //
        //  Internal Methods
        //
        //------------------------------------------------------
        #region Internal Methods
        #endregion

        //------------------------------------------------------
        //
        //  Private Methods
        //
        //------------------------------------------------------
        #region Private Methods
        #endregion

        //------------------------------------------------------
        //
        //  Event Handlers
        //
        //------------------------------------------------------
        #region Event Handlers
        #endregion

        //------------------------------------------------------
        //
        //  Fields
        //
        //------------------------------------------------------
        #region Fields

        private const string itemsPanelName = "PART_ContextualTabItemsGroupPanel";

        #endregion

        //------------------------------------------------------
        //
        //  Events
        //
        //------------------------------------------------------
        #region Events
        #endregion

        //------------------------------------------------------
        //
        //  IRibbonControl Implementation
        //
        //------------------------------------------------------
        #region IRibbonControl Implementation

        /// <summary>
        /// Gets a boolean value indicating whether the contol's size is large
        /// </summary>
        public bool IsLarge
        {
            get { return true; }
        }

        #endregion
    }
}
